package com.comtrade.activities;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.ExecutionException;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Notification;
import android.app.NotificationManager;
import android.bluetooth.BluetoothAdapter;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.PointF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

import com.android.devicehive.device.Device;
import com.comtrade.device.TestDevice;
import com.dataart.android.devicehive.DeviceData;
import com.comtrade.device.BeaconApkConfig;
import com.comtrade.device.TestDevice;
import com.comtrade.device.TestDevice.RegistrationListener;
import com.comtrade.device.TestEquipment;
import com.comtrade.ilserver.tasks.BeaconServer;
import com.comtrade.ilserver.tasks.ConnectTask;
import com.comtrade.ilserver.tasks.Space;
import com.comtrade.ilserver.tasks.User;
import com.comtrade.map.BeaconView;
import com.comtrade.map.MapFrame;
import com.comtrade.mathematics.BeaconRacun;
import com.comtrade.mathematics.Circle;
import com.dataart.android.devicehive.DeviceClass;
import com.dataart.android.devicehive.DeviceData;
import com.dataart.android.devicehive.Network;
import com.comtrade.mathematics.Circle;
import com.comtrade.sharedpreferences.DomesticSharedPreferences;
import com.dataart.android.devicehive.DeviceClass;
import com.dataart.android.devicehive.Network;
import com.estimote.sdk.Beacon;
import com.estimote.sdk.BeaconManager;
import com.estimote.sdk.BeaconManager.MonitoringListener;
import com.estimote.sdk.Region;
import com.estimote.sdk.Utils;
import com.example.beaconapk.R;

public class DeviceActivity extends Activity implements 
RegistrationListener, SensorEventListener{
	private static final String TAG = "DeviceActivity";

	public static final String EXTRAS_TARGET_ACTIVITY = "extrasTargetActivity";
	public static final String EXTRAS_BEACON = "extrasBeacon";
	private static final int REQUEST_ENABLE_BT = 1234;
	private static final Region ALL_ESTIMOTE_BEACONS_REGION = new Region("rid",
			null, null, null);

	private NotificationManager notificationManager;
	private DomesticSharedPreferences sharedPreferences;
	PointF currnetPosition;

	private BeaconManager beaconManager;

	private List<Parameter> parameters = new LinkedList<Parameter>();
	private User korisnik;
	private TestDevice device;

	public static class Parameter {
		public final String name;
		public final float value;

		public Parameter(String name, float value) {
			this.name = name;
			this.value = value;
		}
	}

	private SensorManager mSensorManager;
	private float currentDegree = 0f;
	private MapFrame mp;
	private Sensor orjentacija;

	Drawable image;

	private ArrayList<BeaconServer> listaBikonaIzProstora;
	private List<Beacon> listaBikonaSkeniranih;


	String ilsSeverUri;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		// Setting up Content of Activity				
		mp=new MapFrame(this);
		setContentView(mp);

		mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
		notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

		Intent i = getIntent();
		byte[] nizbitova=(byte[]) i.getExtras().get("image");
		sharedPreferences = new DomesticSharedPreferences();

		ConnectTask ct = new ConnectTask();
		//Slanje podataka na server						
		ct.setPassword(sharedPreferences.getPreferences(getApplicationContext(), "PASSWORD"));
		ct.setUsername(sharedPreferences.getPreferences(getApplicationContext(), "USERNAME"));		
		ct.execute(sharedPreferences.getPreferences(getApplicationContext(), "URL")+"/rest/signin");

		try {

			String result = ct.get();

			korisnik = User.fromJSON(result);
			Log.d("RESULT","kr"+result);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ExecutionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		Space prostor= (Space)i.getExtras().get("space");
		Bitmap pozadina=BitmapFactory.decodeByteArray(nizbitova,0,nizbitova.length);
		int w,h;
		w=Math.abs(prostor.getSpaceCoordinates().get(0).getX()-prostor.getSpaceCoordinates().get(1).getX());
		h=Math.abs(prostor.getSpaceCoordinates().get(0).getY()-prostor.getSpaceCoordinates().get(1).getY());
		mp.getTouchView().setMap(new BitmapDrawable(getResources(), pozadina),w,h);
		Vector<BeaconView> positions= new Vector<BeaconView>();

		listaBikonaIzProstora= prostor.getBeacons();
		for (BeaconServer beaconServer : listaBikonaIzProstora) {
			positions.add(new BeaconView(this,(float)beaconServer.getX(),(float)beaconServer.getY(),beaconServer.getMessage(),mp.getTouchView()));
			Log.d("Bikoni", beaconServer.getX()+" "+beaconServer.getY()+" "+beaconServer.getMessage());
		}
		mp.getTouchView().setBeaconsPositions(positions);




		//Setting up DeviceHive
		parameters = new LinkedList<Parameter>();
		currnetPosition = new PointF();
		Network network = new Network(
				prostor.getTitle(), //space name
				""); //desc

		DeviceClass deviceClass = new DeviceClass(
				"Indoor Location Device", "1.0");

		DeviceData data = new DeviceData(korisnik.getUuid(), 
				"4D6B0A4A-CA77-4164-AAB0-52A7FE3DBD76", 
				korisnik.getFirstName()+" "+korisnik.getSurname(),
				DeviceData.DEVICE_STATUS_ONLINE, 
				deviceClass);
		device = new TestDevice(getApplicationContext(), data); 

		// Podesavanje iBeacon
		beaconManager = new BeaconManager(this);
		beaconManager.setRangingListener(new BeaconManager.RangingListener() {
			@Override
			public void onBeaconsDiscovered(Region region, final List<Beacon> discoveredBeacons) {
				listaBikonaSkeniranih = discoveredBeacons;
				Log.d(TAG, listaBikonaIzProstora.toString());

				// Note that results are not delivered on UI thread.
				new Thread(new Runnable() {
					@Override
					public void run() {
						// Note that beacons reported here are already sorted by
						// estimated
						// distance between device and beacon.

						/* Porvera da li se nalazi u mapi beacon sa tom mac adresom
						 * ako se ne nalazi pravi novo polje u mapi sa tim kljucem i dodaje novi vektor sa daljinom
						 * inace
						 * 		ako nema barem 6 vrednosti upisanih za taj kljuc
						 * 			dodaje udaljenos u vektor
						 * 		else
						 * 			racuna prosek 6 vrednosti, stavlja u beaconDistances mapu i resetuje RSSI List
						 */

						runOnUiThread(new Runnable() {

							@Override
							public void run() {

								int br=0;
								for (Beacon beacon : listaBikonaSkeniranih) {
									br++;
								}
								if (br!=0){
									double distanca = Math.round(Utils.computeAccuracy(listaBikonaSkeniranih.get(0)));
									if(distanca<=1.0f)
										postNotification(1,"One iBeacon is near you, approximately "+distanca+" meters");								
								}



								updateMap();
							}


						});

					}
				}).start();

			}
		});

		beaconManager.setMonitoringListener(new MonitoringListener() {

			@Override
			public void onExitedRegion(Region arg0) {

				Toast.makeText(getApplicationContext(), "OUT", Toast.LENGTH_SHORT).show();
			}

			@Override
			public void onEnteredRegion(Region arg0, List<Beacon> arg1) {

			}
		});

	}

	private void postNotification(int id, String msg) {
		Notification.Builder notification = new Notification.Builder(this)
		.setSmallIcon(R.drawable.beacon_gray)
		.setContentTitle("iBeacon Proximity")
		.setContentText(msg);

		notificationManager.notify(id, notification.build());
	}



	private void updateMap() {

		Vector<BeaconRacun> beacons = new Vector<BeaconRacun>();

		Log.d("device", "prostor "+listaBikonaIzProstora.size());
		Log.d("device", "skenirai "+listaBikonaSkeniranih.size());

		for (Beacon skeniran : listaBikonaSkeniranih) {
			for (BeaconServer izProstora : listaBikonaIzProstora) {

				Log.e(TAG, skeniran.getMacAddress() + " == " + izProstora.getMacAddress());
				if(skeniran.getMacAddress().equalsIgnoreCase(izProstora.getMacAddress()))
				{
					float x = (float)izProstora.getX(); 
					float y = (float)izProstora.getY();
					//Log.d("device", "beacon size= ");
					BeaconRacun br = new BeaconRacun(new PointF(x,y), Utils.computeAccuracy(skeniran));
					br.setMac(skeniran.getMacAddress());
					beacons.add(br);

				}
			}
			Log.d("device", "===============");
		}


		Log.d("device", beacons.toString());

		if(beacons.size()>2)
		{


			Log.e(TAG, ""+beacons.size());
			Vector<PointF> points = Circle.potential_points(beacons);
			Log.e(TAG, points.toString());

			final PointF tacka = Circle.kandidat(points);


			if(tacka != null && !Float.isNaN(tacka.x) && !Float.isNaN(tacka.y)){
				runOnUiThread(new Runnable() {
					public void run() {
						if (tacka.x != currnetPosition.x || tacka.y != currnetPosition.y){
							parameters.clear();
							addParameter("x", tacka.x);
							addParameter("y", tacka.y);
							sendDeviceDataNotification();
							Log.d(TAG, ""+tacka.x + " " + tacka.y);
							mp.getDotView().setCoordinates(tacka.x*100, tacka.y*100);
						}

					}
				});

			}
		}
	}

	private void sendDeviceDataNotification() {

		HashMap<String, Object> parameters = paramsAsMap(this.parameters);

		device.getDeviceData().setData(parameters);
		device.registerDevice();
	}

	private void connectToService() {
		beaconManager.connect(new BeaconManager.ServiceReadyCallback() {
			@Override
			public void onServiceReady() {
				try {
					beaconManager.startRanging(ALL_ESTIMOTE_BEACONS_REGION);
					beaconManager.startMonitoring(ALL_ESTIMOTE_BEACONS_REGION);
				} catch (RemoteException e) {
					Toast.makeText(
							DeviceActivity.this,
							"Cannot start ranging, something terrible happened",
							Toast.LENGTH_LONG).show();
					Log.e(TAG, "Cannot start ranging", e);
				}
			}
		});
	}

	@Override
	protected void onStart() {
		super.onStart();

		// Check if device supports Bluetooth Low Energy.
		if (!beaconManager.hasBluetooth()) {
			Toast.makeText(this, "Device does not have Bluetooth Low Energy",
					Toast.LENGTH_LONG).show();
			return;
		}

		// If Bluetooth is not enabled, let user enable it.
		if (!beaconManager.isBluetoothEnabled()) {
			Intent enableBtIntent = new Intent(
					BluetoothAdapter.ACTION_REQUEST_ENABLE);
			startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
		} else {
			connectToService();
		}
	}

	@Override
	protected void onResume() {
		super.onResume();

		// Device
		/*DomesticSharedPreferences shared = new DomesticSharedPreferences();
		String url = shared.UzmiSamoIP(shared.getPreferences(getApplicationContext(), "URL"));*/

		device.setApiEnpointUrl(BeaconApkConfig.URI_DH_DEFAULT+"/rest");
		device.addDeviceListener(this);
		if (!device.isRegistered()) {
			device.registerDevice();
		} else {
			device.startProcessingCommands();
		}


		// iBeacons

		orjentacija =  mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
		mSensorManager.registerListener(this, orjentacija, SensorManager.SENSOR_DELAY_GAME);

	}

	@Override
	public void onBackPressed() {
		// TODO Auto-generated method stub
		//super.onBackPressed();
		Intent i = new Intent(this, LoginActivity.class);
		startActivity(i);
	}

	@Override
	protected void onPause() {
		mSensorManager.unregisterListener(this);
		super.onPause();

		if (isFinishing()) {
			device.unregisterDevice();
		}
	}

	@Override
	protected void onStop() {
		// iBeacons
		try {
			beaconManager.stopRanging(ALL_ESTIMOTE_BEACONS_REGION);
		} catch (RemoteException e) {
			Log.d(TAG, "Error while stopping ranging", e);
		}

		super.onStop();
	}


	@Override
	protected void onDestroy() {
		//disconnect device 
		device.removeDeviceListener(this);

		if (isFinishing()) {
			device.unregisterDevice();
		}
		// iBeacoons
		beaconManager.disconnect();

		super.onDestroy();
	}

	/*
	 *     ///////// DEVICE \\\\\\\\\\\ 
	 */

	@Override
	public void onDeviceRegistered() {
		Toast.makeText(getApplicationContext(), "Device registred!", Toast.LENGTH_SHORT).show();
	}

	@Override
	public void onDeviceFailedToRegister() {
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		final AlertDialog dialog = builder
				.setTitle("Error")
				.setMessage("Failed to register device")
				.setPositiveButton("Retry",
						new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog,
							int which) {
						device.registerDevice();
					}
				})
				.setNegativeButton("Cancel",
						new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog,
							int which) {
						dialog.dismiss();
						finishActivity(0);
					}
				}).create();
		dialog.show();
	}

	protected void showDialog(String title, String message) {
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		final AlertDialog dialog = builder.setTitle(title).setMessage(message)
				.setPositiveButton("OK", new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
						dialog.dismiss();
					}
				}).create();
		dialog.show();
	}

	protected void showErrorDialog(String message) {
		showDialog("Error!", message);
	}


	private static final int SETTINGS_REQUEST_CODE = 0x01;

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		if (requestCode == SETTINGS_REQUEST_CODE && resultCode == RESULT_OK) {
			Log.d(TAG, "Changed settings!");
			device.unregisterDevice();
			device.setApiEnpointUrl(BeaconApkConfig.URI_DH_DEFAULT+"/rest");
		}
	}

	public void addParameter(String name, float value) {
		this.parameters.add(new Parameter(name, value));
	}

	private static HashMap<String, Object> paramsAsMap(List<Parameter> params) {
		HashMap<String, Object> paramsMap = new HashMap<String, Object>();
		for (Parameter param : params) {
			paramsMap.put(param.name, param.value);
		}
		return paramsMap;
	}


	/*
	 * INIT FOR MENU
	 * 
	 * (non-Javadoc)
	 * @see android.app.Activity#onCreateOptionsMenu(android.view.Menu)
	 */
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// Handle action bar item clicks here. The action bar will
		// automatically handle clicks on the Home/Up button, so long
		// as you specify a parent activity in AndroidManifest.xml.
		int id = item.getItemId();
		if (id == R.id.action_settings) {
			Intent intent = new Intent(this, LoginActivity.class);
			startActivity(intent);
			return true;
		}
		return super.onOptionsItemSelected(item);
	}

	@Override
	public void onAccuracyChanged(Sensor arg0, int arg1) {
		// TODO Auto-generated method stub

	}

	//@Override
	public void onSensorChanged(SensorEvent event) {
		/*/ TODO Auto-generated method stub
		float degree = Math.round(event.values[0]);
<<<<<<< .mine
		Log.d("STEPEN", ""+degree);

>>>>>>> .r81
		RotateAnimation ra = new RotateAnimation(currentDegree, -degree, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,0.5f);
		ra.setDuration(210);
		ra.setFillAfter(true);
		mp.getTouchView().startAnimation(ra);

		mp.getTouchView().rotiraj(currentDegree, degree);
		if(currentDegree<degree) currentDegree = +degree;
		else if(currentDegree>degree) currentDegree=-degree;
=======

		mp.getTouchView().rotiraj(currentDegree, degree);		
		currentDegree = degree;
>>>>>>> .r95
		Log.d("zezanje",""+currentDegree);*/

	}
}
